After the filtering steps and self-assignment results from 02- coupled with some investigation into mis-identified samples in 04-, it’s clear there are some fish that should be excluded (helvomaculatus, brevispinis, simulator) and others with incorrect meta data (maliger).
Here I clean up those things and see what the assignment looks like.
I also want to add some meta data to the samples so that I can understand any oddities - like with the hopkinsi…
library(tidyverse)
library(rubias)
# data
two_col <- read_csv("csv_outputs/sebastes_spp_baseline_two_col.csv")
Parsed with column specification:
cols(
.default = col_integer(),
sample_type = col_character(),
repunit = col_character(),
collection = col_character(),
indiv = col_character()
)
See spec(...) for full column specifications.
# previous mis-assignments at the 95% level
mis <- read_csv("csv_outputs/baseline_misassignments95.csv")
Parsed with column specification:
cols(
indiv = col_character(),
collection = col_character(),
repunit = col_character(),
inferred_collection = col_character(),
inferred_repunit = col_character(),
scaled_likelihood = col_double(),
log_likelihood = col_double(),
z_score = col_double(),
n_non_miss_loci = col_integer(),
n_miss_loci = col_integer()
)
mis
# metadata
meta <- readRDS("../new_baseline_data/processed/meta-data-tibble.rds")
# from the nsf data, I know there are duplicates in the meta data
From this, swap the identity of the maliger (actually caurinus); remove the helvomaculatus, simulator, and brevispinis.
new2col <- two_col %>%
mutate(repunit = ifelse(indiv == "R035252", "caurinus", repunit)) %>%
mutate(collection = ifelse(indiv == "R035252", "caurinus", collection)) %>%
filter(!repunit %in% c("helvomaculatus", "simulator", "brevispinis"))
new2col %>%
write_csv("csv_outputs/new2col.csv")
Now try self-assignment to see where the rest of the misassignments fall.
# perform self-assignment of reference samples
new_self <- self_assign(new2col, gen_start_col = 5)
# correct assigments at the 95% threshold?
new_self %>%
filter(repunit == inferred_repunit) %>%
filter(scaled_likelihood > 0.95)
That is 1,579 of 1,647
1579/1647
[1] 0.9587128
95.9% accurate assignment at the 95% threshold. Great.
# and take a quick look at the misassignments
new_miss <- new_self %>%
filter(inferred_repunit != repunit) %>%
filter(scaled_likelihood > 0.95) # 9 high confidence mis-assignments
new_miss %>%
filter(repunit %in% c("carnatus", "chrysomelas")) # 8 of those assignments are gopher/black-and-yellow
8/9
[1] 0.8888889
And for misassignments at a lower threshold?
new_self %>%
filter(scaled_likelihood > 0.5 & scaled_likelihood < 0.95) %>%
filter(!collection %in% c("carnatus", "chrysomelas"))
Warning in `[<-.data.frame`(`*tmp*`, is_list, value = list(`11` = "<>")) :
replacement element 1 has 1 row to replace 0 rows
All 59 intermediate misassignments are gopher/black-and-yellow.
Misassignments without gopher/black-and-yellow
new_self %>%
filter(inferred_repunit != repunit) %>%
filter(scaled_likelihood > 0.95) %>%
filter(!collection %in% c("carnatus", "chrysomelas"))
That made all of the other strong misassignments, with the exception of R013353 go away.
Based on the PCA, let’s take a look at misassigned caurinus samples:
new_self %>%
filter(collection == "caurinus") %>%
filter(scaled_likelihood > 0.5) %>%
arrange(z_score)
There are four caurinus samples with z-scores < -2; one of which is -12! This gives credence to the idea that they are another species, maybe not in the baseline? Or hybrids?
Still not sure what to think about the one that assigned to carnatus. Check meta data?
For the assignment accuracy:
new_self %>%
filter(repunit == inferred_repunit) %>%
filter(scaled_likelihood > 0.95)
1579/1647
95.87% accurately assigned at the 95% threshold
new_self %>%
filter(collection %in% c("carnatus", "chrysomelas")) %>%
filter(scaled_likelihood > 0.95)
287/346 total GBY
287/346
Lower accuracy for GBY (83%)
Were all mis-id’s to the other species?
new_self %>%
filter(collection %in% c("carnatus", "chrysomelas")) %>%
filter(scaled_likelihood > 0.5) %>%
filter(!inferred_collection %in% c("carnatus", "chrysomelas"))
A single sample assigned to caurinus, but with a z-score of -10!
z-score outliers
Now I’m curious how many of these samples may be from species outside of our baseline according to the z-scores
new_self %>%
filter(scaled_likelihood > 0.5) %>%
filter(z_score < -3) %>%
#filter(z_score > 3) %>%
arrange(z_score) %>%
select(indiv, repunit, inferred_repunit, scaled_likelihood, z_score) %>%
left_join(., meta, by = c("indiv" = "NMFS_DNA_ID")) %>%
select(-PHENOTYPE, HATCHERY_MARK, TAG_NUMBER, ESTIMATED_DATE, LANDFALL_PORT, CRUISE, HAUL)
Hmmm - a bunch of juveniles. What happens if I remove juvenile samples from the analysis?
For most of these samples, they assign to their reported unit even though they have low z-scores.
Test out making a genepop file without the z-score outliers
Just to test it out, I’m going to remove these outliers from the baseline and then perform rubias’s mixture assignment with them.
Now that the data are separated and formatted, do the mixture assignment
mix_zs
$mixing_proportions
$indiv_posteriors
$mix_prop_traces
$bootstrapped_proportions
NA
mix_zs$indiv_posteriors %>%
filter(PofZ > 0.5) %>%
select(mixture_collection, collection, PofZ, z_score, n_miss_loci) %>%
filter(z_score > -3)
single GBY reporting unit
Since all of the intermediate assignments and 8/9 of the high confidence misassignments are GBY, let’s use a single reporting unit for them.
Now try self-assignment with the single reporting unit
gby_repu_assigned <- gby_repu_2col %>%
self_assign(., gen_start_col = 5)
Summary Statistics:
1647 Individuals in Sample
90 Loci: Plate_1_A01_Sat_GW603857_consensus.1, Plate_1_A11_Sat_GE820299_consensus.1, Plate_2_A09_Sat_EW986980_consensus.1, Plate_2_C08_Sat_EW987116_consensus.1, Plate_2_G06_Sat_EW987118_consensus.1, Plate_3_C03_Sat_GE798118_consensus.1, Plate_4_E10_Sat_EW976030_consensus.1, Plate_4_G06_Sat_EW976181_consensus.1, tag_id_1049.1, tag_id_108.1, tag_id_1184.1, tag_id_1229.1, tag_id_1272.1, tag_id_1366.1, tag_id_1428.1, tag_id_143.1, tag_id_1441.1, tag_id_1449.1, tag_id_1471.1, tag_id_1498.1, tag_id_1558.1, tag_id_1576.1, tag_id_1598.1, tag_id_1604.1, tag_id_1613.1, tag_id_162.1, tag_id_1652.1, tag_id_170.1, tag_id_1708.1, tag_id_1748.1, tag_id_1751.1, tag_id_1762.1, tag_id_179.1, tag_id_1804.1, tag_id_1808.1, tag_id_1810.1, tag_id_1836.1, tag_id_1850.1, tag_id_1880.1, tag_id_1889.1, tag_id_1915.1, tag_id_1950.1, tag_id_1961.1, tag_id_1966.1, tag_id_1982.1, tag_id_1994.1, tag_id_1999.1, tag_id_2008.1, tag_id_2009.1, tag_id_2017.1, tag_id_2062.1, tag_id_2082.1, tag_id_2114.1, tag_id_2134.1, tag_id_2155.1, tag_id_2178.1, tag_id_2182.1, tag_id_220.1, tag_id_2203.1, tag_id_221.1, tag_id_2214.1, tag_id_2237.1, tag_id_2247.1, tag_id_2258.1, tag_id_2301.1, tag_id_2319.1, tag_id_2368.1, tag_id_2499.1, tag_id_250.1, tag_id_2607.1, tag_id_2635.1, tag_id_265.1, tag_id_325.1, tag_id_402.1, tag_id_410.1, tag_id_436.1, tag_id_55.1, tag_id_572.1, tag_id_67.1, tag_id_770.1, tag_id_788.1, tag_id_843.1, tag_id_855.1, tag_id_874.1, tag_id_875.1, tag_id_879.1, tag_id_913.1, tag_id_942.1, tag_id_981.1, tag_id_987.1
53 Reporting Units: aleutianus, alutus, atrovirens, auriculatus, aurora, babcocki, borealis, chrysomelas, caurinus, chlorostictus, constellatus, crameri, dallii, diaconus, diploproa, elongatus, emphaeus, ensifer, entomelas, flavidus, goodei, hopkinsi, jordani, levis, maliger, melanops, melanostictus, melanostomus, miniatus, moseri, mystinus, nebulosus, nigrocinctus, oculatus, ovalis, paucispinis, pinniger, polyspinis, proriger, rastrelliger, reedi, rosaceus, ruberrimus, rubrivinctus, rufinanus, rufus, saxicola, semicinctus, serranoides, serriceps, umbrosus, wilsoni, zacentrus
54 Collections: aleutianus, alutus, atrovirens, auriculatus, aurora, babcocki, borealis, carnatus, caurinus, chlorostictus, chrysomelas, constellatus, crameri, dallii, diaconus, diploproa, elongatus, emphaeus, ensifer, entomelas, flavidus, goodei, hopkinsi, jordani, levis, maliger, melanops, melanostictus, melanostomus, miniatus, moseri, mystinus, nebulosus, nigrocinctus, oculatus, ovalis, paucispinis, pinniger, polyspinis, proriger, rastrelliger, reedi, rosaceus, ruberrimus, rubrivinctus, rufinanus, rufus, saxicola, semicinctus, serranoides, serriceps, umbrosus, wilsoni, zacentrus
6.6140457397288% of allelic data identified as missing
gby_repu_assigned %>%
filter(repunit == inferred_repunit) %>%
#filter(scaled_likelihood > 0.95) %>%
filter(repunit %in% c("carnatus", "chrysomelas"))
1586/1647
[1] 0.962963
That only bumps it up to 96.3% accurate assignment because there are still lesser assignments (> 0.95)
playing with int hz
int_hz <- t1 %>%
group_by(collection, indiv, Locus) %>%
summarise(hz = allele[1]!=allele[2]) %>%
filter(!is.na(hz)) %>%
group_by(indiv, collection) %>%
summarise(num_loc = n(), num_hz = sum(hz), fract_hz = num_hz / num_loc)
And now let us plot that.

This is really only useful if the colors of phylogenetically relevant.
Or I could take a subset of the species:

What about making a series of boxplots?
box <- ggplot(int_hz) +
geom_boxplot(aes(x = collection, y = fract_hz, fill = collection), position = "dodge") +
theme_bw() +
xlab("Species") +
ylab("Internal heterozygosity")
box +
theme(
axis.text.x = element_text(angle = 90)
)

Summary Statistics The lower and upper hinges correspond to the first and third quartiles (the 25th and 75th percentiles).
The upper whisker extends from the hinge to the largest value no further than 1.5 x IQR from the hinge (where IQR is the inter-quartile range, or distance between the first and third quartiles). The lower whisker extends from the hinge to the smallest value at most 1.5 x IQR of the hinge. Data beyond the end of the whiskers are called “outlying” points and are plotted individually.
I still want to set the species phylogenetically rather than alphabetically!

Can we also examine the difference from the mean hz of atrovirens?
int_hz %>%
group_by(collection) %>%
summarise(mean_hz = mean(fract_hz)) %>%
arrange(desc(mean_hz)) %>%
mutate(diff = mean_hz/0.46478647) %>%
mutate(perc = diff*100) %>%
filter(diff < 0.5)
LS0tCnRpdGxlOiAiY2xlYW4gYmFzZWxpbmUiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCkFmdGVyIHRoZSBmaWx0ZXJpbmcgc3RlcHMgYW5kIHNlbGYtYXNzaWdubWVudCByZXN1bHRzIGZyb20gYDAyLWAgY291cGxlZCB3aXRoIHNvbWUgaW52ZXN0aWdhdGlvbiBpbnRvIG1pcy1pZGVudGlmaWVkIHNhbXBsZXMgaW4gYDA0LWAsIGl0J3MgY2xlYXIgdGhlcmUgYXJlIHNvbWUgZmlzaCB0aGF0IHNob3VsZCBiZSBleGNsdWRlZCAoaGVsdm9tYWN1bGF0dXMsIGJyZXZpc3BpbmlzLCBzaW11bGF0b3IpIGFuZCBvdGhlcnMgd2l0aCBpbmNvcnJlY3QgbWV0YSBkYXRhIChtYWxpZ2VyKS4KCkhlcmUgSSBjbGVhbiB1cCB0aG9zZSB0aGluZ3MgYW5kIHNlZSB3aGF0IHRoZSBhc3NpZ25tZW50IGxvb2tzIGxpa2UuCgpJIGFsc28gd2FudCB0byBhZGQgc29tZSBtZXRhIGRhdGEgdG8gdGhlIHNhbXBsZXMgc28gdGhhdCBJIGNhbiB1bmRlcnN0YW5kIGFueSBvZGRpdGllcyAtIGxpa2Ugd2l0aCB0aGUgaG9wa2luc2kuLi4KCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShydWJpYXMpCgojIGRhdGEKdHdvX2NvbCA8LSByZWFkX2NzdigiY3N2X291dHB1dHMvc2ViYXN0ZXNfc3BwX2Jhc2VsaW5lX3R3b19jb2wuY3N2IikKCiMgcHJldmlvdXMgbWlzLWFzc2lnbm1lbnRzIGF0IHRoZSA5NSUgbGV2ZWwKbWlzIDwtIHJlYWRfY3N2KCJjc3Zfb3V0cHV0cy9iYXNlbGluZV9taXNhc3NpZ25tZW50czk1LmNzdiIpCgptaXMKCiMgbWV0YWRhdGEKbWV0YSA8LSByZWFkUkRTKCIuLi9uZXdfYmFzZWxpbmVfZGF0YS9wcm9jZXNzZWQvbWV0YS1kYXRhLXRpYmJsZS5yZHMiKQoKIyBmcm9tIHRoZSBuc2YgZGF0YSwgSSBrbm93IHRoZXJlIGFyZSBkdXBsaWNhdGVzIGluIHRoZSBtZXRhIGRhdGEKYGBgCkZyb20gdGhpcywgc3dhcCB0aGUgaWRlbnRpdHkgb2YgdGhlIG1hbGlnZXIgKGFjdHVhbGx5IGNhdXJpbnVzKTsgcmVtb3ZlIHRoZSBoZWx2b21hY3VsYXR1cywgc2ltdWxhdG9yLCBhbmQgYnJldmlzcGluaXMuCgpgYGB7cn0KbmV3MmNvbCA8LSB0d29fY29sICU+JQogIG11dGF0ZShyZXB1bml0ID0gaWZlbHNlKGluZGl2ID09ICJSMDM1MjUyIiwgImNhdXJpbnVzIiwgcmVwdW5pdCkpICU+JQogIG11dGF0ZShjb2xsZWN0aW9uID0gaWZlbHNlKGluZGl2ID09ICJSMDM1MjUyIiwgImNhdXJpbnVzIiwgY29sbGVjdGlvbikpICU+JQogIGZpbHRlcighcmVwdW5pdCAlaW4lIGMoImhlbHZvbWFjdWxhdHVzIiwgInNpbXVsYXRvciIsICJicmV2aXNwaW5pcyIpKQoKbmV3MmNvbCAlPiUKICB3cml0ZV9jc3YoImNzdl9vdXRwdXRzL25ldzJjb2wuY3N2IikKCmBgYAoKTm93IHRyeSBzZWxmLWFzc2lnbm1lbnQgdG8gc2VlIHdoZXJlIHRoZSByZXN0IG9mIHRoZSBtaXNhc3NpZ25tZW50cyBmYWxsLgoKYGBge3IgcnVuLXJ1Ymlhc30KIyBwZXJmb3JtIHNlbGYtYXNzaWdubWVudCBvZiByZWZlcmVuY2Ugc2FtcGxlcwpuZXdfc2VsZiA8LSBzZWxmX2Fzc2lnbihuZXcyY29sLCBnZW5fc3RhcnRfY29sID0gNSkKYGBgCgpgYGB7ciBjb3JyZWN0LWFzc2lnbn0KIyBjb3JyZWN0IGFzc2lnbWVudHMgYXQgdGhlIDk1JSB0aHJlc2hvbGQ/Cm5ld19zZWxmICU+JQogIGZpbHRlcihyZXB1bml0ID09IGluZmVycmVkX3JlcHVuaXQpICU+JQogIGZpbHRlcihzY2FsZWRfbGlrZWxpaG9vZCA+IDAuOTUpCmBgYApUaGF0IGlzIDEsNTc5IG9mIDEsNjQ3CmBgYHtyfQoxNTc5LzE2NDcKYGBgCjk1LjklIGFjY3VyYXRlIGFzc2lnbm1lbnQgYXQgdGhlIDk1JSB0aHJlc2hvbGQuIEdyZWF0LgoKYGBge3IgbWlzcy1hc3NpZ259CiMgYW5kIHRha2UgYSBxdWljayBsb29rIGF0IHRoZSBtaXNhc3NpZ25tZW50cwpuZXdfbWlzcyA8LSBuZXdfc2VsZiAlPiUKICBmaWx0ZXIoaW5mZXJyZWRfcmVwdW5pdCAhPSByZXB1bml0KSAlPiUKICBmaWx0ZXIoc2NhbGVkX2xpa2VsaWhvb2QgPiAwLjk1KSAjIDkgaGlnaCBjb25maWRlbmNlIG1pcy1hc3NpZ25tZW50cwoKbmV3X21pc3MgJT4lCiAgZmlsdGVyKHJlcHVuaXQgJWluJSBjKCJjYXJuYXR1cyIsICJjaHJ5c29tZWxhcyIpKSAjIDggb2YgdGhvc2UgYXNzaWdubWVudHMgYXJlIGdvcGhlci9ibGFjay1hbmQteWVsbG93Cgo4LzkKCmBgYAoKQW5kIGZvciBtaXNhc3NpZ25tZW50cyBhdCBhIGxvd2VyIHRocmVzaG9sZD8KCmBgYHtyfQpuZXdfc2VsZiAlPiUKICBmaWx0ZXIoc2NhbGVkX2xpa2VsaWhvb2QgPiAwLjUgJiBzY2FsZWRfbGlrZWxpaG9vZCA8IDAuOTUpICU+JQogIGZpbHRlcighY29sbGVjdGlvbiAlaW4lIGMoImNhcm5hdHVzIiwgImNocnlzb21lbGFzIikpCmBgYApBbGwgNTkgaW50ZXJtZWRpYXRlIG1pc2Fzc2lnbm1lbnRzIGFyZSBnb3BoZXIvYmxhY2stYW5kLXllbGxvdy4KCk1pc2Fzc2lnbm1lbnRzIHdpdGhvdXQgZ29waGVyL2JsYWNrLWFuZC15ZWxsb3cKYGBge3J9Cm5ld19zZWxmICU+JQogIGZpbHRlcihpbmZlcnJlZF9yZXB1bml0ICE9IHJlcHVuaXQpICU+JQogIGZpbHRlcihzY2FsZWRfbGlrZWxpaG9vZCA+IDAuOTUpICU+JQogIGZpbHRlcighY29sbGVjdGlvbiAlaW4lIGMoImNhcm5hdHVzIiwgImNocnlzb21lbGFzIikpCmBgYAoKVGhhdCBtYWRlIGFsbCBvZiB0aGUgb3RoZXIgc3Ryb25nIG1pc2Fzc2lnbm1lbnRzLCB3aXRoIHRoZSBleGNlcHRpb24gb2YgYFIwMTMzNTNgIGdvIGF3YXkuCgpCYXNlZCBvbiB0aGUgUENBLCBsZXQncyB0YWtlIGEgbG9vayBhdCBtaXNhc3NpZ25lZCBjYXVyaW51cyBzYW1wbGVzOgpgYGB7cn0KbmV3X3NlbGYgJT4lCiAgZmlsdGVyKGNvbGxlY3Rpb24gPT0gImNhdXJpbnVzIikgJT4lCiAgZmlsdGVyKHNjYWxlZF9saWtlbGlob29kID4gMC41KSAlPiUKICBhcnJhbmdlKHpfc2NvcmUpCmBgYApUaGVyZSBhcmUgZm91ciBjYXVyaW51cyBzYW1wbGVzIHdpdGggei1zY29yZXMgPCAtMjsgb25lIG9mIHdoaWNoIGlzIC0xMiEgClRoaXMgZ2l2ZXMgY3JlZGVuY2UgdG8gdGhlIGlkZWEgdGhhdCB0aGV5IGFyZSBhbm90aGVyIHNwZWNpZXMsIG1heWJlIG5vdCBpbiB0aGUgYmFzZWxpbmU/IE9yIGh5YnJpZHM/CgpTdGlsbCBub3Qgc3VyZSB3aGF0IHRvIHRoaW5rIGFib3V0IHRoZSBvbmUgdGhhdCBhc3NpZ25lZCB0byBjYXJuYXR1cy4KQ2hlY2sgbWV0YSBkYXRhPwoKRm9yIHRoZSBhc3NpZ25tZW50IGFjY3VyYWN5OgpgYGB7cn0KbmV3X3NlbGYgJT4lCiAgZmlsdGVyKHJlcHVuaXQgPT0gaW5mZXJyZWRfcmVwdW5pdCkgJT4lCiAgZmlsdGVyKHNjYWxlZF9saWtlbGlob29kID4gMC45NSkKYGBgCgpgYGB7cn0KMTU3OS8xNjQ3CmBgYAo5NS44NyUgYWNjdXJhdGVseSBhc3NpZ25lZCBhdCB0aGUgOTUlIHRocmVzaG9sZAoKYGBge3J9Cm5ld19zZWxmICU+JQogIGZpbHRlcihjb2xsZWN0aW9uICVpbiUgYygiY2FybmF0dXMiLCAiY2hyeXNvbWVsYXMiKSkgJT4lCiAgZmlsdGVyKHNjYWxlZF9saWtlbGlob29kID4gMC45NSkKYGBgCgoyODcvMzQ2IHRvdGFsIEdCWQoKYGBge3J9CjI4Ny8zNDYKYGBgCkxvd2VyIGFjY3VyYWN5IGZvciBHQlkgKDgzJSkKCldlcmUgYWxsIG1pcy1pZCdzIHRvIHRoZSBvdGhlciBzcGVjaWVzPwpgYGB7cn0KbmV3X3NlbGYgJT4lCiAgZmlsdGVyKGNvbGxlY3Rpb24gJWluJSBjKCJjYXJuYXR1cyIsICJjaHJ5c29tZWxhcyIpKSAlPiUKICBmaWx0ZXIoc2NhbGVkX2xpa2VsaWhvb2QgPiAwLjUpICU+JQogIGZpbHRlcighaW5mZXJyZWRfY29sbGVjdGlvbiAlaW4lIGMoImNhcm5hdHVzIiwgImNocnlzb21lbGFzIikpCmBgYApBIHNpbmdsZSBzYW1wbGUgYXNzaWduZWQgdG8gY2F1cmludXMsIGJ1dCB3aXRoIGEgei1zY29yZSBvZiAtMTAhCgoKIyMgei1zY29yZSBvdXRsaWVycwoKTm93IEknbSBjdXJpb3VzIGhvdyBtYW55IG9mIHRoZXNlIHNhbXBsZXMgbWF5IGJlIGZyb20gc3BlY2llcyBvdXRzaWRlIG9mIG91ciBiYXNlbGluZSBhY2NvcmRpbmcgdG8gdGhlIHotc2NvcmVzCgpgYGB7cn0KbmV3X3NlbGYgJT4lCiAgZmlsdGVyKHNjYWxlZF9saWtlbGlob29kID4gMC41KSAlPiUKICBmaWx0ZXIoel9zY29yZSA8IC0zKSAlPiUKICAjZmlsdGVyKHpfc2NvcmUgPiAzKSAlPiUKICBhcnJhbmdlKHpfc2NvcmUpICU+JQogIHNlbGVjdChpbmRpdiwgcmVwdW5pdCwgaW5mZXJyZWRfcmVwdW5pdCwgc2NhbGVkX2xpa2VsaWhvb2QsIHpfc2NvcmUpICU+JQogIGxlZnRfam9pbiguLCBtZXRhLCBieSA9IGMoImluZGl2IiA9ICJOTUZTX0ROQV9JRCIpKSAlPiUKICBzZWxlY3QoLVBIRU5PVFlQRSwgSEFUQ0hFUllfTUFSSywgVEFHX05VTUJFUiwgRVNUSU1BVEVEX0RBVEUsIExBTkRGQUxMX1BPUlQsIENSVUlTRSwgSEFVTCkKYGBgCkhtbW0gLSBhIGJ1bmNoIG9mIGp1dmVuaWxlcy4gV2hhdCBoYXBwZW5zIGlmIEkgcmVtb3ZlIGp1dmVuaWxlIHNhbXBsZXMgZnJvbSB0aGUgYW5hbHlzaXM/CgpGb3IgbW9zdCBvZiB0aGVzZSBzYW1wbGVzLCB0aGV5IGFzc2lnbiB0byB0aGVpciByZXBvcnRlZCB1bml0IGV2ZW4gdGhvdWdoIHRoZXkgaGF2ZSBsb3cgei1zY29yZXMuCgpUZXN0IG91dCBtYWtpbmcgYSBnZW5lcG9wIGZpbGUgd2l0aG91dCB0aGUgei1zY29yZSBvdXRsaWVycwpgYGB7cn0KIyB3aGljaCBvbmVzIHRvIGV4bHVkZQpvdXRsaWVycyA8LSBuZXdfc2VsZiAlPiUKICBmaWx0ZXIoc2NhbGVkX2xpa2VsaWhvb2QgPiAwLjUpICU+JQogIGZpbHRlcih6X3Njb3JlIDwgLTMpICU+JQogIHNlbGVjdChpbmRpdikKCiMgcmVtb3ZlIHRoZXNlIGZyb20gdGhlIG5ldyB0d28tY29sIGZpbGUKZm9yX2dlbmVwb3AgPC0gbmV3MmNvbCAlPiUKICBhbnRpX2pvaW4oLiwgb3V0bGllcnMsIGJ5ID0gImluZGl2IikgJT4lCiAgc2VsZWN0KDM6MTg0KQoKIyBmb3JfZ2VuZXBvcCAlPiUKIyAgIHJlYWRfY3N2KCJjc3Zfb3V0cHV0cy9uZXdfYmFzZWxpbmVfenNjb3Jlc19ub19oZWx2X2V0Yy5jc3YiKQpgYGAKCkp1c3QgdG8gdGVzdCBpdCBvdXQsIEknbSBnb2luZyB0byByZW1vdmUgdGhlc2Ugb3V0bGllcnMgZnJvbSB0aGUgYmFzZWxpbmUgYW5kIHRoZW4gcGVyZm9ybSBydWJpYXMncyBtaXh0dXJlIGFzc2lnbm1lbnQgd2l0aCB0aGVtLgoKYGBge3J9Cm5vX3pzIDwtIG5ldzJjb2wgJT4lCiAgYW50aV9qb2luKC4sIG91dGxpZXJzLCBieSA9ICJpbmRpdiIpCgpqdXN0X3pzIDwtIG5ldzJjb2wgJT4lCiAgcmlnaHRfam9pbiguLCBvdXRsaWVycywgYnkgPSAiaW5kaXYiKSAlPiUKICBtdXRhdGUoc2FtcGxlX3R5cGUgPSAibWl4dHVyZSIpCgpgYGAKCk5vdyB0aGF0IHRoZSBkYXRhIGFyZSBzZXBhcmF0ZWQgYW5kIGZvcm1hdHRlZCwgZG8gdGhlIG1peHR1cmUgYXNzaWdubWVudApgYGB7cn0KbWl4X3pzIDwtIGluZmVyX21peHR1cmUocmVmZXJlbmNlID0gbm9fenMsIG1peHR1cmUgPSBqdXN0X3pzLCBnZW5fc3RhcnRfY29sID0gNSkKYGBgCgoKYGBge3J9Cm1peF96cyRpbmRpdl9wb3N0ZXJpb3JzICU+JQogIGZpbHRlcihQb2ZaID4gMC41KSAlPiUKICBzZWxlY3QobWl4dHVyZV9jb2xsZWN0aW9uLCBjb2xsZWN0aW9uLCBQb2ZaLCB6X3Njb3JlLCBuX21pc3NfbG9jaSkgJT4lCiAgZmlsdGVyKHpfc2NvcmUgPiAtMykKYGBgCgoKCgojIyBzaW5nbGUgR0JZIHJlcG9ydGluZyB1bml0CgpTaW5jZSBhbGwgb2YgdGhlIGludGVybWVkaWF0ZSBhc3NpZ25tZW50cyBhbmQgOC85IG9mIHRoZSBoaWdoIGNvbmZpZGVuY2UgbWlzYXNzaWdubWVudHMgYXJlIEdCWSwgbGV0J3MgdXNlIGEgc2luZ2xlIHJlcG9ydGluZyB1bml0IGZvciB0aGVtLgoKYGBge3J9CiMgY2hhbmdlIHRoZSBjYXJuYXR1cyByZXBvcnRpbmcgdW5pdCB0byBjaHJ5c29tZWxhcwpnYnlfcmVwdV8yY29sIDwtIG5ldzJjb2wgJT4lCiAgbXV0YXRlKHJlcHVuaXQgPSBpZmVsc2UocmVwdW5pdCA9PSAiY2FybmF0dXMiLCAiY2hyeXNvbWVsYXMiLCByZXB1bml0KSkKCiMgY29uZmlybSB0aGF0IHRoZSByZXB1bml0IGlzIGNoYW5nZWQgYnV0IHRoZSBjb2xsZWN0aW9uIGlzIG5vdC4KZ2J5X3JlcHVfMmNvbCAlPiUKICBmaWx0ZXIoY29sbGVjdGlvbiA9PSAiY2FybmF0dXMiKQpgYGAKCk5vdyB0cnkgc2VsZi1hc3NpZ25tZW50IHdpdGggdGhlIHNpbmdsZSByZXBvcnRpbmcgdW5pdApgYGB7cn0KZ2J5X3JlcHVfYXNzaWduZWQgPC0gZ2J5X3JlcHVfMmNvbCAlPiUKICBzZWxmX2Fzc2lnbiguLCBnZW5fc3RhcnRfY29sID0gNSkKCmBgYAoKYGBge3J9CmdieV9yZXB1X2Fzc2lnbmVkICU+JQogIGZpbHRlcihyZXB1bml0ID09IGluZmVycmVkX3JlcHVuaXQpICU+JQogIGZpbHRlcihzY2FsZWRfbGlrZWxpaG9vZCA+IDAuOTUpICU+JQogIGZpbHRlcihyZXB1bml0ICVpbiUgYygiY2FybmF0dXMiLCAiY2hyeXNvbWVsYXMiKSkKYGBgCgpgYGB7cn0KMTU4Ni8xNjQ3CmBgYApUaGF0IG9ubHkgYnVtcHMgaXQgdXAgdG8gOTYuMyUgYWNjdXJhdGUgYXNzaWdubWVudCBiZWNhdXNlIHRoZXJlIGFyZSBzdGlsbCBsZXNzZXIgYXNzaWdubWVudHMgKD4gMC45NSkKCgojIyBwbGF5aW5nIHdpdGggaW50IGh6CgpgYGB7cn0KdDEgPC0gZm9yX2dlbmVwb3AgJT4lCiAgZ3JvdXBfYnkoaW5kaXYsIGNvbGxlY3Rpb24pICU+JQogIGdhdGhlcihsb2N1cywgYWxsZWxlLCAzOjE4MikgJT4lCiAgdW5ncm91cCgpICU+JSAjIG5lZWQgdG8gcmVtb3ZlIHRoZSAuMSBhbmQgLjIgb24gdGhlIGxvY2kKICBzZXBhcmF0ZShsb2N1cywgYygiTG9jdXMiLCAiZ2VuZS5jb3B5IiksIHNlcCA9ICJbLl0iKQpgYGAKCgpgYGB7ciBjb21wdXRlLWludC1oenN9CmludF9oeiA8LSB0MSAlPiUgCiAgZ3JvdXBfYnkoY29sbGVjdGlvbiwgaW5kaXYsIExvY3VzKSAlPiUgCiAgc3VtbWFyaXNlKGh6ID0gYWxsZWxlWzFdIT1hbGxlbGVbMl0pICU+JSAKICBmaWx0ZXIoIWlzLm5hKGh6KSkgJT4lIAogIGdyb3VwX2J5KGluZGl2LCBjb2xsZWN0aW9uKSAlPiUgCiAgc3VtbWFyaXNlKG51bV9sb2MgPSBuKCksIG51bV9oeiA9IHN1bShoeiksIGZyYWN0X2h6ID0gbnVtX2h6IC8gbnVtX2xvYykKCmBgYApBbmQgbm93IGxldCB1cyBwbG90IHRoYXQuCmBgYHtyIHBsb3QtaW50LWh6LCBmaWcud2lkdGg9MTJ9CmdncGxvdChpbnRfaHosIGFlcyh4ID0gZnJhY3RfaHosIGZpbGwgPSBjb2xsZWN0aW9uKSkgKwogIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuMykgKwogIHRoZW1lX2J3KCkgKwogIHhsYWIoIkludGVybmFsIGhldGVyb3p5Z29zaXR5IikgKwogIHlsYWIoIkRlbnNpdHkiKQoKZ2dzYXZlKCJwZGZfb3V0cHV0cy9pbnQtaHpfcGxvdC5wZGYiLCBoZWlnaHQgPSA2LCB3aWR0aCA9IDEwKQoKYGBgClRoaXMgaXMgcmVhbGx5IG9ubHkgdXNlZnVsIGlmIHRoZSBjb2xvcnMgb2YgcGh5bG9nZW5ldGljYWxseSByZWxldmFudC4KCk9yIEkgY291bGQgdGFrZSBhIHN1YnNldCBvZiB0aGUgc3BlY2llczoKYGBge3J9CnNwX2tlZXAgPC0gYygiYXVyb3JhIiwgImRpcGxvcHJvYSIsICJvY3VsYXR1cyIsICJyb3NhY2V1cyIsICJjaGxvcm9zdGljdHVzIiwgIm5pZ3JvY2luY3R1cyIsICJydWZ1cyIsICJvdmFsaXMiLCAiZ29vZGVpIiwgImxldmlzIiwgIm15c3RpbnVzIiwgImZsYXZpZHVzIiwgImF0cm92aXJlbnMiLCAiY2F1cmludXMiLCAibmVidWxvc3VzIiwgInJhc3RyZWxsaWdlciIsICJzYXhpY29sYSIsICJlbG9uZ2F0dXMiLCAibWluaWF0dXMiLCAicnViZXJyaW11cyIsICJyZWVkaSIsImFsZXV0aWFudXMiLCAid2lsc29uaSIsICJwcm9yaWdlciIpCgojIGZhY3Rvcl9zcGtlZXAgPC0gZmFjdG9yKHNwX2tlZXApCiMgbGV2ZWxzKGZhY3Rvcl9zcGtlZXApIDwtIGMoImF1cm9yYSIsICJkaXBsb3Byb2EiLCAib2N1bGF0dXMiLCAicm9zYWNldXMiLCAiY2hsb3Jvc3RpY3R1cyIsICJuaWdyb2NpbmN0dXMiLCAicnVmdXMiLCAib3ZhbGlzIiwgImdvb2RlaSIsICJsZXZpcyIsICJteXN0aW51cyIsICJmbGF2aWR1cyIsICJhdHJvdmlyZW5zIiwgImNhdXJpbnVzIiwgIm5lYnVsb3N1cyIsICJyYXN0cmVsbGlnZXIiLCAic2F4aWNvbGEiLCAiZWxvbmdhdHVzIiwgIm1pbmlhdHVzIiwgInJ1YmVycmltdXMiLCAicmVlZGkiLCJhbGV1dGlhbnVzIiwgIndpbHNvbmkiLCAicHJvcmlnZXIiKQoKCnN1YiA8LSBpbnRfaHogJT4lCiAgZmlsdGVyKGNvbGxlY3Rpb24gJWluJSBsZXZlbHMoZmFjdG9yX3Nwa2VlcCkpCgojIGxldmVscyhzdWIkY29sbGVjdGlvbikgPC0gYygiYXVyb3JhIiwgImRpcGxvcHJvYSIsICJvY3VsYXR1cyIsICJyb3NhY2V1cyIsICJjaGxvcm9zdGljdHVzIiwgIm5pZ3JvY2luY3R1cyIsICJydWZ1cyIsICJvdmFsaXMiLCAiZ29vZGVpIiwgImxldmlzIiwgIm15c3RpbnVzIiwgImZsYXZpZHVzIiwgImF0cm92aXJlbnMiLCAiY2F1cmludXMiLCAibmVidWxvc3VzIiwgInJhc3RyZWxsaWdlciIsICJzYXhpY29sYSIsICJlbG9uZ2F0dXMiLCAibWluaWF0dXMiLCAicnViZXJyaW11cyIsICJyZWVkaSIsImFsZXV0aWFudXMiLCAid2lsc29uaSIsICJwcm9yaWdlciIpCgpnZ3Bsb3Qoc3ViLCBhZXMoeCA9IGZyYWN0X2h6LCBmaWxsID0gY29sbGVjdGlvbikpICsKICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjMpICsKICB0aGVtZV9idygpICsKICB4bGFiKCJJbnRlcm5hbCBoZXRlcm96eWdvc2l0eSIpICsKICB5bGFiKCJEZW5zaXR5IikKCiNnZ3Bsb3QoInBkZl9vdXRwdXRzL2ludC1oei1zdWJzZXQucGRmIiwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNSkKYGBgCgpXaGF0IGFib3V0IG1ha2luZyBhIHNlcmllcyBvZiBib3hwbG90cz8KCmBgYHtyfQpib3ggPC0gZ2dwbG90KGludF9oeikgKwogIGdlb21fYm94cGxvdChhZXMoeCA9IGNvbGxlY3Rpb24sIHkgPSBmcmFjdF9oeiwgZmlsbCA9IGNvbGxlY3Rpb24pLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsKICB0aGVtZV9idygpICsKICB4bGFiKCJTcGVjaWVzIikgKwogIHlsYWIoIkludGVybmFsIGhldGVyb3p5Z29zaXR5IikKCgpib3ggKwogIHRoZW1lKAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCkKICApCmBgYApTdW1tYXJ5IFN0YXRpc3RpY3MKVGhlIGxvd2VyIGFuZCB1cHBlciBoaW5nZXMgY29ycmVzcG9uZCB0byB0aGUgZmlyc3QgYW5kIHRoaXJkIHF1YXJ0aWxlcyAodGhlIDI1dGggYW5kIDc1dGggcGVyY2VudGlsZXMpLiAKClRoZSB1cHBlciB3aGlza2VyIGV4dGVuZHMgZnJvbSB0aGUgaGluZ2UgdG8gdGhlIGxhcmdlc3QgdmFsdWUgbm8gZnVydGhlciB0aGFuIDEuNSB4IElRUiBmcm9tIHRoZSBoaW5nZSAod2hlcmUgSVFSIGlzIHRoZSBpbnRlci1xdWFydGlsZSByYW5nZSwgb3IgZGlzdGFuY2UgYmV0d2VlbiB0aGUgZmlyc3QgYW5kIHRoaXJkIHF1YXJ0aWxlcykuIFRoZSBsb3dlciB3aGlza2VyIGV4dGVuZHMgZnJvbSB0aGUgaGluZ2UgdG8gdGhlIHNtYWxsZXN0IHZhbHVlIGF0IG1vc3QgMS41IHggSVFSIG9mIHRoZSBoaW5nZS4gRGF0YSBiZXlvbmQgdGhlIGVuZCBvZiB0aGUgd2hpc2tlcnMgYXJlIGNhbGxlZCAib3V0bHlpbmciIHBvaW50cyBhbmQgYXJlIHBsb3R0ZWQgaW5kaXZpZHVhbGx5LgoKSSBzdGlsbCB3YW50IHRvIHNldCB0aGUgc3BlY2llcyBwaHlsb2dlbmV0aWNhbGx5IHJhdGhlciB0aGFuIGFscGhhYmV0aWNhbGx5IQpgYGB7cn0KIyBzZXQgdGhlIGxldmVscyBleHBsaWNpdGx5CmludF9oeiRjb2xsZWN0aW9uIDwtIGZhY3RvcihpbnRfaHokY29sbGVjdGlvbiwgbGV2ZWxzID0gYygiYXRyb3ZpcmVucyIsICJjaHJ5c29tZWxhcyIsICJjYXJuYXR1cyIsICJjYXVyaW51cyIsICJtYWxpZ2VyIiwgIm5lYnVsb3N1cyIsICJkYWxsaWkiLCJyYXN0cmVsbGlnZXIiLCAiYXVyaWN1bGF0dXMiLCAic2F4aWNvbGEiLCAic2VtaWNpbmN0dXMiLCAiZWxvbmdhdHVzIiwgIm1pbmlhdHVzIiwgInBpbm5pZ2VyIiwgIm9jdWxhdHVzIiwgImNvbnN0ZWxsYXR1cyIsICJ1bWJyb3N1cyIsICJyb3NhY2V1cyIsICJjaGxvcm9zdGljdHVzIiwgImVuc2lmZXIiLCAiYmFiY29ja2kiLCAibmlncm9jaW5jdHVzIiwgInJ1YnJpdmluY3R1cyIsICJzZXJyaWNlcHMiLCAicnVmdXMiLCAib3ZhbGlzIiwgImhvcGtpbnNpIiwgInJ1ZmluYW51cyIsICJtb3NlcmkiLCAiam9yZGFuaSIsICJwYXVjaXNwaW5pcyIsICJnb29kZWkiLCAibGV2aXMiLCAiZW50b21lbGFzIiwgIm15c3RpbnVzIiwgImRpYWNvbnVzIiwgImZsYXZpZHVzIiwgInNlcnJhbm9pZGVzIiwgIm1lbGFub3BzIiwgInJ1YmVycmltdXMiLCAiYXVyb3JhIiwgImRpcGxvcHJvYSIsICJtZWxhbm9zdG9tdXMiLCAicmVlZGkiLCAiY3JhbWVyaSIsICJwb2x5c3BpbmlzIiwgImFsdXR1cyIsICJtZWxhbm9zdGljdHVzIiwgImFsZXV0aWFudXMiLCAiZW1waGFldXMiLCAid2lsc29uaSIsICJ6YWNlbnRydXMiLCAicHJvcmlnZXIiLCAiYm9yZWFsaXMiKSkKCiMgY2hlY2sgdGhhdCB0aGUgbGV2ZWxzIHN0dWNrCmxldmVscyhpbnRfaHokY29sbGVjdGlvbikKCiMgbm93IGJveHBsb3QgaXQKYm94MiA8LSBnZ3Bsb3QoaW50X2h6KSArCiAgZ2VvbV9ib3hwbG90KGFlcyh4ID0gY29sbGVjdGlvbiwgeSA9IGZyYWN0X2h6LCBmaWxsID0gY29sbGVjdGlvbiksIHBvc2l0aW9uID0gImRvZGdlIikgKwogIHRoZW1lX2J3KCkgKwogIHhsYWIoIlNwZWNpZXMiKSArCiAgeWxhYigiSW50ZXJuYWwgaGV0ZXJvenlnb3NpdHkiKQoKCmJveDIgKwogIHRoZW1lKAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgc2l6ZSA9IDEyKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCkKICApICsKICBndWlkZXMoZmlsbCA9IEZBTFNFKQoKZ2dzYXZlKCJwZGZfb3V0cHV0cy9pbnQtaHotYm94cGxvdC5wZGYiLCBoZWlnaHQgPSA4LCB3aWR0aCA9IDEwKQoKYGBgCgpDYW4gd2UgYWxzbyBleGFtaW5lIHRoZSBkaWZmZXJlbmNlIGZyb20gdGhlIG1lYW4gaHogb2YgYXRyb3ZpcmVucz8KYGBge3J9CmludF9oeiAlPiUKICBncm91cF9ieShjb2xsZWN0aW9uKSAlPiUKICBzdW1tYXJpc2UobWVhbl9oeiA9IG1lYW4oZnJhY3RfaHopKSAlPiUKICBhcnJhbmdlKGRlc2MobWVhbl9oeikpICU+JQogIG11dGF0ZShkaWZmID0gbWVhbl9oei8wLjQ2NDc4NjQ3KSAlPiUKICBtdXRhdGUocGVyYyA9IGRpZmYqMTAwKSAlPiUKICBmaWx0ZXIoZGlmZiA8IDAuNSkKYGBgCgo=